/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dg.gaming.client.fx.gui;

import com.dg.gaming.api.common.Game;
import com.dg.gaming.api.common.GameModel;
import com.dg.gaming.api.common.GameOver;
import com.dg.gaming.api.common.IGame;
import com.dg.gaming.api.common.IGameOver;
import com.dg.gaming.api.common.Player;
import com.dg.gaming.api.common.PlayerList;
import com.dg.gaming.api.common.Table;
import com.dg.gaming.api.common.TransmissionException;
import com.dg.gaming.api.common.User;
import com.dg.gaming.api.common.msg.Msg;
import com.dg.gaming.api.common.msg.MsgChatTable;
import com.dg.gaming.api.common.msg.MsgControllerObject;
import com.dg.gaming.api.common.msg.MsgControllerProperty;
import com.dg.gaming.api.common.msg.MsgExitTable;
import com.dg.gaming.api.common.msg.MsgGameOver;
import com.dg.gaming.api.common.msg.MsgInvite;
import com.dg.gaming.api.common.msg.MsgJoinTable;
import com.dg.gaming.api.common.msg.MsgNextPlayer;
import com.dg.gaming.api.common.msg.MsgNoMove;
import com.dg.gaming.api.common.msg.MsgOfferDraw;
import com.dg.gaming.api.common.msg.MsgPlayerState;
import com.dg.gaming.api.common.msg.MsgReadyToStart;
import com.dg.gaming.api.common.msg.MsgSitDown;
import com.dg.gaming.api.common.msg.MsgStandUp;
import com.dg.gaming.api.common.msg.MsgStartGame;
import com.dg.gaming.api.common.msg.MsgTableProperty;
import com.dg.gaming.api.common.playerstate.PlayerState;
import com.dg.gaming.api.common.playerstate.PlayerStateSeated;
import com.dg.gaming.api.common.playerstate.PlayerStateViewing;
import com.dg.gaming.api.common.util.DGLabels;
import com.dg.gaming.client.GameController;
import com.dg.gaming.client.TableConnection;
import com.dg.gaming.client.gui.DGComponent;
import java.util.Observable;
import java.util.Observer;
import nanoxml.XMLElement;

/**
 *
 * @author dito
 */
public class TableMessageReciever implements Observer {
// Declare data fields
     private PlayerList players;
   
    private int numPlayers = IGame.DEFAULT_NUM_OF_PLAYERS;
    // Declare data fields

    protected long userid;
    protected TableConnection conn = null; // Connection
    protected String tableNum; // number of this table
    protected GameModel gameModel = null; // Client gameModel
    protected IGameController gameController = null; // GameController
    
    protected Table table = null;
    protected Game game = null;
    protected Player player = null;
    
    
    // Declare other fields
    private int selectedSeat = -1;
    public TableMessageReciever(TableConnection conn) {
        
        this.conn = conn;
        this.tableNum = conn.getTableNum();
        this.table = conn.getTable();
        this.game = table.getGame();
        this.userid = conn.getUserId();
        this.player = this.table.getPlayerList().getPlayer(userid);

        User user = new User(conn.getUserName(), this.userid, 0, 0, 0, 0, 0);
        player.setUser(user);
        players=table.getPlayerList();
        players.addObserver(this);
    }

    public void receiveTableMessage(XMLElement message) {
        try {
            String messageType = message.getName();
            Game game = table.getGame();
            long userid = conn.getUserId();
            if (messageType.equals(Msg.START_GAME)) {
                MsgStartGame commStartGame = new MsgStartGame(message);
                table.getPlayerList().setCurrentPlayer(commStartGame.getCurrentPlayer());
                startGame(new MsgStartGame(message));
            } else if (messageType.equals(Msg.GAME_OVER)) {
                gameOver(new MsgGameOver(message));
            } else if (messageType.equals(Msg.OFFER_DRAW)) {
                receiveOfferDraw(new MsgOfferDraw(message));
            } else if (messageType.equals(Msg.CONTROLLER_PROPERTY)) {
                receiveProperty(new MsgControllerProperty(message));
            } else if (messageType.equals(Msg.CONTROLLER_OBJECT)) {
                receiveObject(new MsgControllerObject(message));
            } else if (messageType.equals(Msg.CHAT_TABLE)) {
                MsgChatTable commMessage = new MsgChatTable(message);
                receiveChatTableMessage(commMessage.getUserid(),
                        commMessage.getTableNum(),
                        commMessage.getChat());
            } else if (messageType.equals(Msg.JOIN_TABLE)) {
                MsgJoinTable commJoinTable = new MsgJoinTable(message);
                if (commJoinTable.containsModel()) {
                    gameModel.setState(commJoinTable.getModelState());
                }
                receiveJoinTable(new MsgJoinTable(message), userid, table);
            } else if (messageType.equals(Msg.EXIT_TABLE)) {
                MsgExitTable commExitTable = new MsgExitTable(message);
                game.getTableList().removePlayer(commExitTable.getTableNum(),
                        commExitTable.getUserid());
            } else if (messageType.equals(Msg.GAME_OVER)) {
                gameOver(new MsgGameOver(message), userid, table);
            } else if (messageType.equals(Msg.PLAYER_STATE)) {
                playerStateUpdate(new MsgPlayerState(message), table);
            } else if (messageType.equals(Msg.START_GAME)) {
            } else if (messageType.equals(Msg.NEXT_PLAYER)) {
                MsgNextPlayer commNextPlayer = new MsgNextPlayer(message);
                table.getPlayerList().setCurrentPlayer(commNextPlayer.getUserid());
            } else if (messageType.equals(Msg.TABLE_PROPERTY)) {
                MsgTableProperty commTableProperty = new MsgTableProperty(
                        message);
                table.addProperty(commTableProperty.getKey(),
                        commTableProperty.getValue());
            } else if (messageType.equals(MsgNoMove.XML_ATT_NOMOVE)) {
                MsgNoMove nm = new MsgNoMove(message);
                noMove(nm);
            }

        // Also pass message into adapter method which all DG clients
        // can receive to do additional processing if this is required.

        } catch (TransmissionException transEx) {
        }
    }

    private void noMove(MsgNoMove nomove) {
//        timerPanel.startTiming(nomove.getDeley());
    }

    /**
     * Receive a join table message.
     *
     * @param commJoinTable  Join table object.
     * @param username       Username.
     * @param table          Table object.
     */
    private void receiveJoinTable(MsgJoinTable commJoinTable, long userid,
            Table table) {

        PlayerList playerList = commJoinTable.getPlayerList();

        if (playerList == null) {
            // No player list, so just add the single player to the table.
            long joiningPlayerId = commJoinTable.getUserid();
            User joiningUser = game.getUserList().getUser(joiningPlayerId);
            if (joiningUser == null) {
                joiningUser = new User(commJoinTable.getUsername(),
                        joiningPlayerId, 0, 0, 0, 0, 0);
                game.getUserList().addUser(joiningUser);
            }
            table.addPlayer(joiningUser);
        } else {
            // This message has a player list, so use that to set the playerlist
            // at the table.

            // First, Augment the player objects in the playerList with their users.
            playerList.updateUsers(game.getUserList());

            // Now, set the playerlist at the table
            table.setPlayerList(playerList);
        }

        // Update anything depending on tablelist
        game.getTableList().refreshObservers();
    }

    /**
     * Recieve a game over message and update the user objects.
     *
     * @param commGameOver  CommGameOver object.
     * @param username      Username object.
     * @param table         Table number.
     */
    private void gameOver(MsgGameOver commGameOver, long username,
            Table table) {
        // Depending on the status create the game over message
        GameOver gameOver = commGameOver.getGameOver();
        long[] players = gameOver.getPlayers();
        int[] results = gameOver.getResults();
        int[] newRatings = gameOver.getNewRatings();

        // Update ratings of each player
        for (int i = 0; i < players.length; i++) {
            User user = game.getUserList().getUser(players[i]);
            user.update(results[i], newRatings[i]);
        }
        // Up$date table object.
        table.gameOver();

        game.getUserList().refreshObservers();
    }

    /**
     * Player state change i.e. a player is standing up / sitting down etc.
     *
     * @param commPlayerState
     */
    private void playerStateUpdate(MsgPlayerState commPlayerState, Table table) {
        // Retreive state change
        PlayerState commState = commPlayerState.getState();

        // Retreive player
        PlayerList commPlayers = table.getPlayerList();
        Player commPlayer = commPlayers.getPlayer(commPlayerState.getUserid());

        // update state on client player
        if (commState == null || commPlayer == null) {
            System.out.println();
        }
        commPlayer.setState(commState);

        // Check to see if the seat number needs updated.
        if (commState instanceof PlayerStateSeated) {
            commPlayer.setSeatNum(commPlayerState.getSeatNum());
        } else if (commState instanceof PlayerStateViewing) {
            commPlayer.setSeatNum(Player.NOT_SEATED);
        }

        commPlayers.refreshObservers();
    }

    /**
     * Adapter method for receiving a custom message.
     *
     * @see com.dg.gaming.client.gui.ITable#receiveTableMessage(nanoxml.XMLElement)
     */
    /**
     * Receive start game message from server.  Change status of players, reset current
     * player (for turn based games), call controller.start() and startGame() on
     * any sub class of this class.
     *
     * @param commStartGame
     */
    private void startGame(MsgStartGame commStartGame) {
        // Start controller
        this.gameController.start(); // Controller is also informed game is started

        // Delegate to custom startGame () method in client if required
        this.startGame();
    }

    /**
     * Start the game (Empty adapter method).
     */
    public void startGame() {
    }

    /**
     * This client wishes to sit down at a particular table.
     */
    private void sitDown() {
       

        // Create table action communications object and send to server
        MsgSitDown commSitDown = new MsgSitDown(selectedSeat);
        conn.send(commSitDown);
    }

    /**
     * Stand back up again (status of player becomes VIEWING).
     */
    private void standUp() {
        // Set the status of the player back to VIEWING.
        MsgStandUp commStandUp = new MsgStandUp();

        conn.send(commStandUp);
    }

    /**
     * Player clicks the start button.
     */
    private void readyToStart() {
        MsgReadyToStart commReadyToStart = new MsgReadyToStart();
        conn.send(commReadyToStart);
    }

    /**
     * Offer the user a draw.
     */
    private void offerDraw() {
        // Create offer draw communications object and send to server.
        MsgOfferDraw commOfferDraw = new MsgOfferDraw(
                MsgInvite.REQUEST);
        conn.send(commOfferDraw);
    }

    /**
     * Receive offer draw.
     *
     * @param offerDraw
     */
    private void receiveOfferDraw(MsgOfferDraw offerDraw) {
//        DGLabels dgLabels = DGLabels.getInstance();
//
//        // Check to see if this is an offer draw or an offer draw reply
//        if (offerDraw.getStatus() == MsgInvite.REQUEST) {
//
//            String message =
//                    dgLabels.get("player") + " " + offerDraw.getUserid() +
//                    " " +
//                    dgLabels.get("offers.a.draw") + " " +
//                    dgLabels.get("accept") + "?";
//
//            int answer = JOptionPane.showConfirmDialog(
//                    this,
//                    message,
//                    dgLabels.get("table.message"),
//                    JOptionPane.YES_NO_OPTION
//                         );
//
//            // Convert to a number the CommInvite object understands
//            int yesNo = (answer == JOptionPane.YES_OPTION) ?
//                        MsgInvite.ACCEPT : MsgInvite.DECLINE;
//
//            // Create invite comm object to reply to the users
//            MsgOfferDraw offerDrawReply = new MsgOfferDraw(
//                    yesNo, offerDraw.getUserid());
//            offerDrawReply.setSerialNum(offerDraw.getSerialNum());
//
//            // Transmit message back to the server
//            conn.send(offerDrawReply);
//        } else { // is an offer draw reply from a user
//            if (offerDraw.getStatus() == MsgInvite.DECLINE) {
//
//                // report message that user has declined the offer
//                String messageTitle =
//                        "User " + offerDraw.getUserid() + " " +
//                        dgLabels.get("has.rejected.draw.offer") + ".";
//
//                JOptionPane.showMessageDialog(
//                        this,
//                        messageTitle,
//                        dgLabels.get("table.message"),
//                        JOptionPane.INFORMATION_MESSAGE
//                        );
//            }
//        }
    }

    /**
     * Resign from this particular game.
     */
    private void resign() {
        // Player resigns
        MsgGameOver commGameOver = new MsgGameOver(IGameOver.USER_RESIGNS);
        conn.send(commGameOver);
    }

    /**
     * Pop up invite dialog and invite someone to the table
     */
    private void invite() {
//        this.getInviteDialog();
    }

    /**
     * Sets up the MVC for this table.  This method <b>must</b> be called from
     * the constructor of any sub class of this class as this class refers to
     * the GameModel and DGController.
     *
     * @param model
     * @param mainView
     * @param controller
     */
    public void setupMVC(GameModel model, 
            IGameController controller) {
        this.gameModel = model;
        this.gameController = controller;
    }

    /**
     * Create game over message and add to chat box.
     *
     * @param commGameOver
     */
    private void gameOver(MsgGameOver commGameOver) {
        // Create game over message
        DGLabels labels = DGLabels.getInstance();
        StringBuffer fromSB, ratingsSB;

        // Depending on the status create the game over message
        GameOver gameOver = commGameOver.getGameOver();
        long[] players = gameOver.getPlayers();
        int[] results = gameOver.getResults();
        int[] oldRatings = gameOver.getOldRatings();
        int[] newRatings = gameOver.getNewRatings();

        // Loop through the players
        for (int i = 0; i < players.length; i++) {
            int result = results[i];

            // Create from message
            fromSB = new StringBuffer(
                    labels.get("player") + " " + players[i] + " ");
            if (result == IGameOver.DRAW) {
                fromSB.append(labels.get("draws"));
            } else if (result == IGameOver.LOSE) {
                fromSB.append(labels.get("loses"));
            } else if (result == IGameOver.WIN) {
                fromSB.append(labels.get("wins"));
            }

            // Create old / new ratings
            ratingsSB = new StringBuffer(
                    labels.get("old.rating") + " " + oldRatings[i] + " " +
                    labels.get("new.rating") + " " + newRatings[i]);

        // Write to the message component
//            messageComponent.receiveMessage(fromSB.toString(),
//                                            ratingsSB.toString());
        }

        // Display "Game Over" text in glass pane
        StringBuffer gameOverSB = new StringBuffer(labels.get("game.over"));
        int seatNum = player.getSeatNum();
        if (seatNum >= 0 && seatNum < players.length) {
            if (results[seatNum] == IGameOver.DRAW) {
                gameOverSB.append(" - " + labels.get("draw"));
            } else if (results[seatNum] == IGameOver.LOSE) {
                gameOverSB.append(" - " + labels.get("you.lose"));
            } else if (results[seatNum] == IGameOver.WIN) {
                gameOverSB.append(" - " + labels.get("you.win"));
            }
        }
//        glassPane.display(GAME_OVER_FONT, GAME_OVER_COLOUR, gameOverSB.toString());
    }

    /**
     * Receive a property.
     *
     * @param commProperty
     */
    private void receiveProperty(MsgControllerProperty commProperty) {
        // retrieve controller from the correct table.
//        GameController controller = getController();
//
//        switch (commProperty.getStatus()) {
//        case MsgControllerProperty.TYPE_STRING:
//            controller.receiveProperty(commProperty.getKey(),
//                                       commProperty.getValue());
//            return;
//
//        case MsgControllerProperty.TYPE_INT:
//            int value = Integer.parseInt(commProperty.getValue());
//            controller.receiveProperty(commProperty.getKey(), value);
//            return;
//
//        case MsgControllerProperty.TYPE_INT_TWO:
//            StringTokenizer st = new StringTokenizer(commProperty.getValue());
//            int value1 = Integer.parseInt(st.nextToken());
//            int value2 = Integer.parseInt(st.nextToken());
//            controller.receiveProperty(commProperty.getKey(), value1, value2);
//            return;
//        }
    }

    /**
     * Receive a message for a specificied table.
     *
     *
     * @param usernameFrom
     * @param tableNum
     * @param messageText
     */
    private void receiveChatTableMessage(long useridFrom, String tableNum,
            String messageText) {
//        Player p = table.getPlayerList().getPlayer(useridFrom);
//        String usernameFrom = useridFrom + "";
//        if (p != null) {
//            usernameFrom = p.toUserName();
//        }
//        getMessageComponent().receiveMessage(usernameFrom + "", messageText);
    }

    /**
     * Retrieve controller object.
     *
     * @param commObject
     */
    private void receiveObject(MsgControllerObject commObject) {
//        GameController controller = getController();
//        controller.receiveObject(commObject.getData());
    }

    private void refresh() {
        // If a seat isn't selected or a seat isn't free AND a user has sat down yet
        if ((selectedSeat == -1 || !players.isSeatFree(selectedSeat)) &&
                player.getSeatNum() == Player.NOT_SEATED) {
            for (int i = 0; i < numPlayers; i++) {
                if (players.isSeatFree(i)) {
                    selectedSeat = i;
                    break;
                }
            }
        }

//        // Refresh the components
//        for (int i = 0; i < numPlayers; i++) {
//            colourSquares[i].repaint();
//        }
    }

    /**
     * Refresh the available seats component.
     *
     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    public void update(Observable arg0, Object arg1) {
        refresh();
    }
}
